﻿#pragma once
#include <iostream>
#include <vector>
#include<time.h>
using std::cout;
using std::endl;

//********************_Lty***********************//
#ifdef _WIN32
#include<windows.h>
#endif // _WIN32



// 直接去堆上按⻚申请空间
inline static void* SystemAlloc(size_t kpage) // kpage << 13  页数乘以页数的大小 -> 全部需要申请的内存字节大小
{
#ifdef _WIN32
	void* ptr = VirtualAlloc(0, kpage << 13, MEM_COMMIT | MEM_RESERVE,
		PAGE_READWRITE);
#else
	// linux下brk mmap等
#endif
	if (ptr == nullptr)
		throw std::bad_alloc();
	return ptr;
}

//定长内存池 
template<class T>
class Object_pool
{
public:
	T* New()
	{
		//初始化返回内存块的结点
		T* obj = nullptr;
		//优先从freelist中切内存块
		if (freelist)
		{
			//单链表切内存
			void* next = *((void**)freelist);
			obj = (T*)freelist;
			freelist = next;
		}
		else
		{
			//剩余内存不够则会开空间
			if (remain_size < sizeof(T))
			{
				remain_size = 128 * 1024; //初始化内存块的大小 128kb的大小 1024bye等于1kb  
				//pool_head = (char*)malloc(remain_size);
				pool_head = (char*)SystemAlloc(remain_size >> 13);  // 8 * 1024 (一页有8kb的大小)  -> 2 ^ 3 * 2 ^ 10 = 2 ^ 13;
				//直接找堆、系统申请空间 跳过
				if (pool_head == nullptr)
				{
					cout << "pool_head malloc failed" << endl;
				}
			}
			obj = (T*)pool_head;
			//处理内存块的大小  当归还的内存块小于4字节或者8字节时
			size_t object = sizeof(T) < sizeof(void*) ? sizeof(void*) : sizeof(T);
			pool_head += object; //更新定长内存池的头结点
			remain_size -= object;//更新剩余内存块的大小
		}
		//显示调用T的构造函数 定位new -> 已分配的内存块中对空间调用构造函数进行初始化
		new(obj)T;
		return obj;
	}
	//头插的方式归还内存
	void Delete(T* list)
	{
		//显示调用T对象的析构函数 可能是string或者vector
		list->~T();
		//每块内存的头void*的空间来存储 下一个归还内存块的头结点
		*(void**)list = freelist;
		freelist = list;
	}
private:
	char* pool_head = nullptr;//管理定长内存池的头结点
	void* freelist = nullptr;//管理返回的内存块的自由链表-> 单链表
	size_t remain_size = 0; //剩余内存块大小
};


struct TreeNode
{
	int _val;
	TreeNode* _left;
	TreeNode* _right;
	TreeNode()
		:_val(0)
		, _left(nullptr)
		, _right(nullptr)
	{}

	~TreeNode()
	{
		_val = 0;
		delete[]_left;
		delete[]_right;
		_left = _right = nullptr;
	}
};

void TestObjectPool()
{
	// 申请释放的轮次
	const size_t Rounds = 3;
	// 每轮申请释放多少次
	const size_t N = 100000;
	size_t begin1 = clock();
	std::vector<TreeNode*> v1;
	v1.reserve(N);
	for (size_t j = 0; j < Rounds; ++j)
	{
		for (int i = 0; i < N; ++i)
		{
			v1.push_back(new TreeNode);
		}
		for (int i = 0; i < N; ++i)
		{
			delete v1[i];
		}
		v1.clear();
	}


	size_t end1 = clock();
	Object_pool<TreeNode> TNPool;
	size_t begin2 = clock();
	std::vector<TreeNode*> v2;
	v2.reserve(N);
	for (size_t j = 0; j < Rounds; ++j)
	{
		for (int i = 0; i < N; ++i)
		{
			v2.push_back(TNPool.New());
		}
		for (int i = 0; i < N; ++i)
		{
			TNPool.Delete(v2[i]);
		}
		v2.clear();
	}
	size_t end2 = clock();
	cout << "new cost time:" << end1 - begin1 << endl;
	cout << "object pool cost time:" << end2 - begin2 << endl;
}


//********************_Lty***********************//